<template>
  <view class="dl-uploader">
    <view v-if="imgTip" class="img-tip">{{ imgTip }}</view>
    <!--当有多个u-upload组件时，name起作用，共用回调 afterRead方法-->
    <u-upload
      :fileList="fileListArr"
      accept="image"
      :multiple="isMultiple"
      :maxCount="maxCount"
      :uploadIcon="uploadIcon"
      :width="width"
      :height="height"
      :uploadText="uploadText"
      :capture="sourceTypes"
      :beforeRead="enableCompress ? beforeRead : undefined"
      @afterRead="afterRead"
      @delete="deletePic"
    ></u-upload>
  </view>
</template>

<script>
import { getSignature } from '@/utils/signature'
import { getToken } from '@/utils/auth'
import { compressImage } from '@/utils/files'

const APPID = process.env.VUE_APP_ID
const baseURL = process.env.VUE_APP_BASE_URL + process.env.VUE_APP_BASE_API
const uploadUrl = '/common/upload/image'
const timestamp = Date.parse(new Date()) / 1000
const config_ = {
  appid: APPID,
  timestamp
}
const sign = getSignature(uploadUrl, config_)
const action = `${baseURL}${uploadUrl}?timestamp=${timestamp}&appid=${APPID}&sign=${sign}`

export default {
  name: 'UploadImageComponent',
  props: {
    // 顶部文字提示
    imgTip: {
      type: String,
      default: '文件支持jpg、jpeg、png格式,大小0b-10Mb，最多可上传5个文件'
    },
    // 是否支持多个图片同时上传
    multiple: {
      type: Boolean,
      default: true
    },
    // 图片上传最大数量
    maxCount: {
      type: Number,
      default: 5
    },
    // 单个文件最大值
    maxSize: {
      type: Number,
      default: 2 * 1024 * 1024
    },
    // 默认已存在的图片列表
    fileList: {
      type: Array,
      default: () => []
    },
    // 内部预览图片区域和选择图片按钮的区域宽度
    width: {
      type: [String, Number],
      default: uni.$u.props.upload.width
    },
    // 内部预览图片区域和选择图片按钮的区域高度
    height: {
      type: [String, Number],
      default: uni.$u.props.upload.height
    },
    // 上传区域的图标，只能内置图标
    uploadIcon: {
      type: String,
      default: uni.$u.props.upload.uploadIcon
    },
    // 上传区域的提示文字
    uploadText: {
      type: String,
      default: uni.$u.props.upload.uploadText
    },
    // 是否添加水印
    watermarkUrl: {
      type: String,
      default: ''
    },
    // 水印内容
    watermark: {
      type: String,
      default: ''
    },
    // 是否压缩图片
    enableCompress: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      fileListArr: [], // 文件列表
      sourceTypes: ['album', 'camera'] // 图片支持拍摄方式
    }
  },
  watch: {
    fileList: {
      handler(newVal) {
        const isNotEmptyArray = Array.isArray(newVal) && newVal.length > 0
        isNotEmptyArray && (this.fileListArr = newVal)
      }
    }
  },
  computed: {
    /**
     * computed watcher multiple|addWatermark dep
     * watcher.depend(); 根据computed watcher，render watcher multiple|addWatermark dep
     */
    isMultiple: function () {
      return this.multiple && !this.watermarkUrl
    }
  },
  created() {
    /**
     * 在created时
     * 如果父节点传递了addWatermark，则 this.addWatermark 该值是从父节点获取的，否则是默认值
     * 此时已经有了user watcher, computed watcher 但还没有render watcher，所以改变data数据不会引发updated
     */
    this.watermarkUrl && (this.sourceTypes = ['camera'])
  },
  methods: {
    async beforeRead(file) {
      return compressImage(Array.isArray(file) ? file.map(i => i.url) : [file.url])
    },
    async afterRead(event) {
      // console.log(event)
      const lists = [].concat(event.file) // 当设置 multiple 为 true 时, file 为数组格式，否则为对象格式, 本次上传所有文件
      let fileListLen = this.fileListArr.length // 本次上传起点
      lists.map(item => {
        this.fileListArr.push({
          ...item,
          status: 'uploading',
          message: '上传中'
        })
      })

      const addWatermark = !!this.watermarkUrl
      if (addWatermark) {
        uni.navigateTo({
          url: this.watermarkUrl,
          events: {
            updateFileList: this.updateFileList
          },
          success: res => {
            res.eventChannel.emit('tempUrl', { url: lists[0].url, index: event.index, desc: this.watermark })
          }
        })
      } else {
        for (let i = 0; i < lists.length; i++) {
          const result = await this.uploadFilePromise(lists[i].url)
          // 修改fileListArr的状态
          this.fileListArr.splice(
            fileListLen,
            1,
            Object.assign(this.fileListArr[fileListLen], {
              status: 'success',
              message: '',
              url: result
            })
          )
          fileListLen++
        }
        this.emitReferrer()
      }
    },
    uploadFilePromise(url) {
      return new Promise((resolve, reject) => {
        const token = getToken()
        uni.uploadFile({
          name: 'image',
          url: action,
          filePath: url,
          header: {
            Authorization: 'Bearer ' + token
          },
          success: res => {
            const resData = JSON.parse(res.data)
            resolve(resData.data.url)
          },
          fail: res => reject(res)
        })
      })
    },
    async updateFileList({ url, index }) {
      try {
        const res = this.enableCompress ? await compressImage([url]) : [{ url }]
        const result = await this.uploadFilePromise(res[0].url)
        this.fileListArr.splice(
          index,
          1,
          Object.assign(this.fileListArr[index], {
            status: 'success',
            url: result
          })
        )
        this.emitReferrer()
      } catch (err) {
        console.log(err)
      }
    },
    // 删除图片
    deletePic(event) {
      this.fileListArr.splice(event.index, 1)
      this.emitReferrer()
    },
    emitReferrer() {
      const fileList = this.fileListArr.map(file => file.url)
      this.$emit('getFd', fileList)
    }
  }
}
</script>

<style lang="scss">
.dl-uploader {
  .img-tip {
    word-break: break-all;
    font-size: 22rpx;
    color: #9e9e9e;
    line-height: 24rpx;
    margin-bottom: 26rpx;
  }
}
</style>
